package com.pengtu.dao.app;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.DateTools.Resolution;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.CachingWrapperFilter;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryWrapperFilter;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.util.PDFTextStripper;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import org.wltea.analyzer.lucene.IKAnalyzer;
import org.wltea.analyzer.lucene.IKQueryParser;
import org.wltea.analyzer.lucene.IKSimilarity;

import com.pengtu.dao.Page;
import com.pengtu.dao.hibernate.HibernateDao;
import com.pengtu.entity.app.Attachment;
import com.pengtu.utils.DateUtils;
import com.pengtu.utils.FileUtils;

@Repository
public class AttachmentDao extends HibernateDao<Attachment, Serializable> {

	/**
	 * private String partId; // 对应与某一部分 private String tableId; // 对应表id
	 * private String tableName; // 对应某表 private String tableField; // 对应表中的某个字段
	 * getAttachmentList: 适用: 查询
	 * 
	 * @return
	 * @exception
	 * @since 1.0.0
	 */
	public List<Attachment> getAttachmentList(String partId, String tableName,
			String tableId, String tableField) {
		List<Criterion> criterionList = new ArrayList<Criterion>();
		if (StringUtils.isNotEmpty(partId)) {
			Criterion partIdC = Restrictions.eq("partId", partId);
			criterionList.add(partIdC);
		}
		if (StringUtils.isNotEmpty(tableName)) {
			Criterion tableNameC = Restrictions.eq("tableName", tableName);
			criterionList.add(tableNameC);
		}
		if (StringUtils.isNotEmpty(tableId)) {
			Criterion tableIdC = Restrictions.eq("tableId", tableId);
			criterionList.add(tableIdC);
		}
		if (StringUtils.isNotEmpty(tableField)) {
			Criterion tableFieldC = Restrictions.eq("tableField", tableField);
			criterionList.add(tableFieldC);
		}

		return find(criterionList.toArray(new Criterion[criterionList.size()]));
	};

	/**
	 * private String partId; // 对应与某一部分 private String tableId; // 对应表id
	 * private String tableName; // 对应某表 private String tableField; // 对应表中的某个字段
	 * getAttachmentList: 适用: 查询
	 * 
	 * @return
	 * @exception
	 * @since 1.0.0
	 */
	public Page<Attachment> getAttachmentList(Page<Attachment> page,
			String partId, String tableName, String tableId, String tableField) {
		List<Criterion> criterionList = new ArrayList<Criterion>();
		if (StringUtils.isNotEmpty(partId)) {
			Criterion partIdC = Restrictions.eq("partId", partId);
			criterionList.add(partIdC);
		}
		if (StringUtils.isNotEmpty(tableName)) {
			Criterion tableNameC = Restrictions.eq("tableName", tableName);
			criterionList.add(tableNameC);
		}
		if (StringUtils.isNotEmpty(tableId)) {
			Criterion tableIdC = Restrictions.eq("tableId", tableId);
			criterionList.add(tableIdC);
		}
		if (StringUtils.isNotEmpty(tableField)) {
			Criterion tableFieldC = Restrictions.eq("tableField", tableField);
			criterionList.add(tableFieldC);
		}

		return findPage(page,
				criterionList.toArray(new Criterion[criterionList.size()]));
	}

	/**
	 * 
	 * createTableIndexByLucene: 适用:创建附件表索引
	 * 
	 * @param index索引跟目录
	 * @exception
	 * @since 1.0.0
	 */
	public void createTableIndexByLucene(String index) {
		try {
			File fsDir = new File(index + "//attachment//attachTable");
			Analyzer analyzer = new IKAnalyzer();
			IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_31,
					analyzer);
			Directory dir = FSDirectory.open(fsDir);
			iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);// 总是重新创建
			if (IndexWriter.isLocked(dir)) {
				IndexWriter.unlock(dir);
				}
			IndexWriter iw = new IndexWriter(dir, iwc);
			List<Attachment> attachmentList = super.getAll();
			int size = attachmentList.size();
			long startTime = new Date().getTime();
			Document doc;
			//添加到索引里去
			for (Attachment attachment : attachmentList) {
				doc = new Document();
				doc.add(new Field("id", attachment.getId(), Field.Store.YES,
						Field.Index.ANALYZED));
				doc.add(new Field("upfileFileName", attachment
						.getUpfileFileName(), Field.Store.YES,
						Field.Index.ANALYZED));
				doc.add(new Field("uploadPerson", attachment.getUploadPerson(),
						Field.Store.YES, Field.Index.ANALYZED));
				if (attachment.getCreateDate() != null)
					doc.add(new Field("createDate", DateTools.dateToString(
							attachment.getCreateDate(), Resolution.MINUTE),
							Field.Store.YES, Field.Index.NOT_ANALYZED));
				iw.addDocument(doc);
			}
			// 自动优化合并索引文件
			iw.optimize();
			iw.close();

			long endTime = new Date().getTime();
			System.out.println("一共" + size + ",这花费了" + (endTime - startTime)
					+ " 毫秒来把附件表文档增加到索引里面去!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * SearchTableByLucene: 适用:检索附件表中的关键词
	 * 
	 * @param keyword关键词
	 * @param index 检索地址
	 * @param startDate开始时间  格式为 yyyyMMdd 例 20111120 
	 * @param endDate结束时间   格式为 yyyyMMdd 例 20111120 
	 * @return 
	 * @exception 
	 * @since  1.0.0
	 */
	public Set<Attachment> SearchTableByLucene(String index, String keyword,String startDate, String endDate) {
		File fsDir = new File(index + "//attachment//attachTable");
		Analyzer analyzer = new IKAnalyzer();
		Set<Attachment> attachmentList = new HashSet<Attachment>();
		try {
			// 索引查询
			IndexReader reader = IndexReader
					.open(FSDirectory.open(fsDir), true); // only searching, so
															// read-only=true
			IndexSearcher isearcher = new IndexSearcher(reader);

			BooleanQuery booleanQuery = new BooleanQuery();
			Query query;
			query = IKQueryParser.parse("upfileFileName", keyword);// 检索词
			query.setBoost(1.5f);
			booleanQuery.add(query, Occur.SHOULD);

			query = IKQueryParser.parse("uploadPerson", keyword);// 检索词
			query.setBoost(1.0f);
			booleanQuery.add(query, Occur.SHOULD);

			BooleanQuery filterBooleanQuery = new BooleanQuery();
			TermRangeQuery rangeQuery = new TermRangeQuery("createDate",startDate, endDate, true, true);
			filterBooleanQuery.add(rangeQuery, BooleanClause.Occur.MUST);

			// 将booleanQuery封装到Filter中
			Filter filter = new CachingWrapperFilter(new QueryWrapperFilter(
					filterBooleanQuery));

			TopScoreDocCollector collector = TopScoreDocCollector.create(100,
					true);
			isearcher.setSimilarity(new IKSimilarity());
			isearcher.search(booleanQuery, filter, collector);

			ScoreDoc[] hits = collector.topDocs(0, 100).scoreDocs;
			QueryScorer qs = new QueryScorer(IKQueryParser.parse(
					"upfileFileName", keyword));
			QueryScorer qs2 = new QueryScorer(IKQueryParser.parse(
					"uploadPerson", keyword));
			for (ScoreDoc h : hits) {
				Document d = isearcher.doc(h.doc);
				Attachment attach = super.get(d.get("id").toString());
				Attachment attachment = new Attachment();
				attachment.setId(attach.getId());
				attachment.setUploadPerson(attach.getUploadPerson());
				attachment.setCreateDate(attach.getCreateDate());
				attachment.setUpfileFileName(attach.getUpfileFileName());
				attachment.setPath(attach.getPath());
				attachment.setFullPath(attach.getFullPath());
				String upfileFileName = d.get("upfileFileName");
				String uploadPerson = d.get("uploadPerson");
				//高亮效果
				Formatter formatter = new SimpleHTMLFormatter(
						"<font style='background-color:#F9F400;'>", "</font>");

				Highlighter h1 = new Highlighter(formatter, qs);
				Highlighter h2 = new Highlighter(formatter, qs2);
				String upfileFileName2 = h1.getBestFragment(analyzer,
						"upfileFileName", upfileFileName);
				String uploadPerson2 = h2.getBestFragment(analyzer,
						"uploadPerson", uploadPerson);
				if (uploadPerson2 != null) {
					attachment.setUploadPerson(uploadPerson2);
				} else {
					attachment.setUploadPerson(uploadPerson);
				}
				if (upfileFileName2 != null) {
					attachment.setUpfileFileName(upfileFileName2);
				} else {
					attachment.setUpfileFileName(upfileFileName);
				}
				attachment.setCreateDate(DateUtils.toDate(d.get("createDate")));
				attachmentList.add(attachment);
			}
			System.out.println("在附件Table中找到：" + hits.length + " 个");
			isearcher.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
		return attachmentList;
	}

	/**
	 * 
	 * createAttachmentIndexByLucene: 适用:创建附件内容索引
	 * 
	  * @param fileClassPath跟路径
	 * @param index存放索引路径
	 * @throws Exception
	 * @exception
	 * @since 1.0.0
	 */
	public void createAttachmentIndexByLucene(String fileClassPath, String index) {
		try {
			List<File> po = new ArrayList<File>();
			po = FileUtils.getReclusiveDirFile(fileClassPath + "upload", po);
			TreeSet<String> set = new TreeSet<String>();
			for (File ll : po) {
				set.add(ll.getParent());
			}

			/**//* 这里放索引文件的位置 */
			File indexDir = new File(index + "//attachment//upload");
			Analyzer analyzer = new IKAnalyzer();
			IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_31,
					analyzer);
			Directory dir = FSDirectory.open(indexDir);
			iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);// 总是重新创建
			if (IndexWriter.isLocked(dir)) {
				IndexWriter.unlock(dir);
				}
			IndexWriter indexWriter = new IndexWriter(dir, iwc);
			long startTime = new Date().getTime();

			Iterator<String> iter = set.iterator();
			while (iter.hasNext()) {
				String filepath = iter.next();
				// String fileindex = filepath.substring(2);
				/**//* 指明要索引文件夹的位置,这里是C盘的S文件夹下 */
				File fileDir = new File(filepath);

				File[] textFiles = fileDir.listFiles();
				// 增加document到索引去
				for (int i = 0; i < textFiles.length; i++) {
					if (textFiles[i].isFile()) {
						System.out.println(" File  "
								+ textFiles[i].getCanonicalPath()
								+ " 正在被索引.... ");
						String temp = "";
						if (textFiles[i].getName().endsWith(".doc")) {
							temp = readWord(textFiles[i].getCanonicalPath());
						} else if (textFiles[i].getName().endsWith(".pdf")) {
							temp = readPdf(textFiles[i].getCanonicalPath());
						} else if (textFiles[i].getName().endsWith(".html")) {
							temp = readHtml(textFiles[i].getCanonicalPath());
						}
						// else if(textFiles[i].getName().endsWith(".zip")){
						// temp = readZip(textFiles[i].getCanonicalPath() ); }
						else
							temp = FileReaderAll(
									textFiles[i].getCanonicalPath(), "GBK");
						System.out.println(temp);
						Document document = new Document();
						Field FieldPath = new Field("path",
								textFiles[i].getPath(), Field.Store.YES,
								Field.Index.ANALYZED);
						Field FieldBody = new Field("body", temp,
								Field.Store.YES, Field.Index.ANALYZED,
								Field.TermVector.WITH_POSITIONS_OFFSETS);
						document.add(FieldPath);
						document.add(FieldBody);
						indexWriter.addDocument(document);
					}
				}
				// optimize()方法是对索引进行优化
			}
			indexWriter.optimize();
			indexWriter.close();
			// 测试一下索引的时间
			long endTime = new Date().getTime();
			System.out.println(" 这花费了 " + (endTime - startTime)
					+ " 毫秒来把文档内容增加到索引里面去! ");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * FileReaderAll: 适用:
	 * 
	 * @param FileName
	 * @param charset
	 * @return
	 * @throws IOException
	 * @exception
	 * @since 1.0.0
	 */
	public static String FileReaderAll(String FileName, String charset)
			throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				new FileInputStream(FileName), charset));
		String line = new String();
		String temp = new String();

		while ((line = reader.readLine()) != null) {
			temp += line;
		}
		reader.close();
		return temp;
	}

	/**
	 * 
	 * SearchAttachmentByLucene: 适用:检索附件中的关键词
	 * 
	 * @param keyword
	 *            关键词
	 * @param index
	 *            检索地址
	 * @return
	 * @throws InvalidTokenOffsetsException
	 * @exception
	 * @since 1.0.0
	 */
	public Set<Attachment> SearchAttachmentByLucene(String index, String keyword) {
		Query query = null;
		File indexDir = new File(index + "//attachment//upload");
		Set<Attachment> textList = new HashSet<Attachment>();
		try {
			Directory dir = FSDirectory.open(indexDir);
			IndexReader reader = IndexReader.open(dir, true); // only searching,
																// so
																// read-only=true
			IndexSearcher searcher = new IndexSearcher(reader);
			Analyzer analyzer = new IKAnalyzer();
			
			TopScoreDocCollector collector = TopScoreDocCollector.create(100,true);
			query = IKQueryParser.parse("body", keyword);
			if (searcher != null) {
				searcher.search(query, collector);
				ScoreDoc[] hits = collector.topDocs(0, 200).scoreDocs;
				QueryScorer qs = new QueryScorer(query);
				for (ScoreDoc h : hits) {
					Document d = searcher.doc(h.doc);
					String path = d
							.get("path")
							.toString()
							.substring(
									(d.get("path").toString().lastIndexOf("\\")) + 1);
					Attachment attachment = new Attachment();
					attachment = findUniqueBy("path", path);
					String result = d.get("body");
					Formatter formatter = new SimpleHTMLFormatter(
							"<font style='background-color:#F9F400;'>",
							"</font>");
					Highlighter h1 = new Highlighter(formatter, qs);
					String result2 = h1.getBestFragment(analyzer, "body",
							result);
					result2 = com.pengtu.utils.StringUtils.changeHTML(result2);
					result2 = result2.replace("&lt;font&nbsp;", "<font ")
							.replace("'&gt;", "'>")
							.replace("&lt;/font", "</font")
							.replace("font&gt;", "font>");
					attachment.setResult(result2);
					textList.add(attachment);
				}
				System.out.println(" 在附件内容中找到: " + hits.length + "  个结果! ");

			}
			searcher.close();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		return textList;
	}

	/**
	 * 
	 * readWord: 适用:WORD文档
	 * 
	 * @param path
	 * @return
	 * @exception
	 * @since 1.0.0
	 */
	public static String readWord(String path) {
		StringBuffer content = new StringBuffer("");// 文档内容
		try {

			HWPFDocument doc = new HWPFDocument(new FileInputStream(path));
			Range range = doc.getRange();
			int paragraphCount = range.numParagraphs();// 段落
			for (int i = 0; i < paragraphCount; i++) {// 遍历段落读取数据
				Paragraph pp = range.getParagraph(i);
				content.append(pp.text());
			}

		} catch (Exception e) {

		}
		return content.toString().trim();
	}

	/**
	 * 
	 * readPdf: 适用:Pdf
	 * 
	 * @param path
	 * @return
	 * @throws Exception
	 * @exception
	 * @since 1.0.0
	 */
	public static String readPdf(String path) throws Exception {
		StringBuffer content = new StringBuffer("");// 文档内容
		FileInputStream fis = new FileInputStream(path);
		PDFParser p = new PDFParser(fis);
		p.parse();
		PDFTextStripper ts = new PDFTextStripper();
		content.append(ts.getText(p.getPDDocument()));
		fis.close();
		return content.toString().trim();
	}

	/**
	 * 
	 * readHtml: 适用:
	 * 
	 * @param urlString
	 * @return
	 * @exception
	 * @since 1.0.0
	 */
	public static String readHtml(String urlString) {

		StringBuffer content = new StringBuffer("");
		File file = new File(urlString);
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
			// 读取页面
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					fis, "utf-8"));// 这里的字符编码要注意，要对上html头文件的一致，否则会出乱码

			String line = null;

			while ((line = reader.readLine()) != null) {
				content.append(line + "\n");
			}
			reader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		String contentString = content.toString();
		return contentString;
	}

	/**
	 * 
	 * createIndexByLucene:
	 * 适用:
	 * @param fileClassPath跟路径
	 * @param index存放索引路径
	 * @throws Exception 
	 * @exception 
	 * @since  1.0.0
	 */
	public void createIndexByLucene(String fileClassPath, String index) {
		createTableIndexByLucene(index);
		createAttachmentIndexByLucene(fileClassPath, index);
	}

	/**
	 * 
	 * SearchByLucene:
	 * 适用:
	 * @param keyword关键词
	 * @param index 检索地址
	 * @param startDate开始时间  格式为 yyyyMMdd 例 20111120 
	 * @param endDate结束时间   格式为 yyyyMMdd 例 20111120 
	 * @return 
	 * @exception 
	 * @since  1.0.0
	 */
	public Collection<Attachment> SearchByLucene(String index, String keyword,String startDate, String endDate) {
		Set<Attachment> sA = SearchAttachmentByLucene(index, keyword);
		Set<Attachment> sT = SearchTableByLucene(index,keyword,startDate,endDate);
		sA.addAll(sT);
		return sA;
	}

	@SuppressWarnings("unchecked")
	public List<Attachment> getAttachmentLists(String partId, String tableName,
			String tableField, String upfileFileName) {
		List<Criterion> criterionList = new ArrayList<Criterion>();
		if (StringUtils.isNotEmpty(partId)) {
			Criterion partIdC = Restrictions.eq("partId", partId);
			criterionList.add(partIdC);
		}
		if (StringUtils.isNotEmpty(tableName)) {
			Criterion tableNameC = Restrictions.ilike("tableName", tableName,MatchMode.ANYWHERE);
			criterionList.add(tableNameC);
		}
		if (StringUtils.isNotEmpty(tableField)) {
			Criterion tableIdC = Restrictions.ilike("tableField", tableField,MatchMode.ANYWHERE);
			criterionList.add(tableIdC);
		}
		if (StringUtils.isNotEmpty(upfileFileName)) {
			Criterion tableFieldC = Restrictions.ilike("upfileFileName", upfileFileName,MatchMode.ANYWHERE);
			criterionList.add(tableFieldC);
		}
		Criteria criteria = createCriteria(criterionList.toArray(new Criterion[criterionList.size()]));
		criteria.addOrder(Order.desc("tableName"));
		return criteria.list();
	};
}
